//
//  BMSOpMergeReporter.m
//  WDBMS
//
//  Created by YeJary on 2025/5/13.
//

//  BMSOpMergeReporter.m
//  WDBMS

//
//  BMSOpMergeReporter.m
//  WDBMS
//
//  Created by YeJary on 2025/5/13.
//

#import "BMSOpMergeReporter.h"
#import "BMSOpMergeEventBuilder.h"
#import "BMSInitializer.h"
#import "BMSAPIService.h"
#import "BMSNetworkDefines.h"
#import "BMSEncryptionUtil.h"
#import "BMSAppInfoHelper.h"
#import "BMSOpMergeCacheManager.h"
#import <UIKit/UIKit.h>

#define kBMSCachedEventsKey @"kBMSCachedEventsKey"

@interface BMSOpMergeReporter ()
@property (nonatomic, strong) NSMutableArray<NSDictionary *> *eventCache;
@property (nonatomic, strong) dispatch_queue_t syncQueue;
@property (nonatomic, strong) NSTimer *flushTimer;
@property (nonatomic, assign) NSInteger uploadInterval;
@property (nonatomic, copy) NSString *lastTraceId;
@property (nonatomic, assign) NSUInteger totalUploadedCount;
@property (nonatomic, assign) NSUInteger totalFailedCount;
@end

@implementation BMSOpMergeReporter

+ (instancetype)shared {
    static BMSOpMergeReporter *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

- (instancetype)init {
    if (self = [super init]) {
        _eventCache = [NSMutableArray array];
        _syncQueue = dispatch_queue_create("com.bms.reporter.queue", DISPATCH_QUEUE_SERIAL);
        _uploadInterval = 30;
        [self loadCacheFromDisk];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate) name:UIApplicationWillTerminateNotification object:nil];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(appDidFinishLaunching:) name:UIApplicationDidFinishLaunchingNotification object:nil];
    }
    return self;
}

- (void)configureWithInterval:(NSInteger)seconds {
    self.uploadInterval = MAX(10, seconds);
    [self startFlushTimer];
}

- (void)startFlushTimer {
    [self.flushTimer invalidate];
    self.flushTimer = [NSTimer scheduledTimerWithTimeInterval:self.uploadInterval
                                                       target:self
                                                     selector:@selector(flushEvents)
                                                     userInfo:nil
                                                      repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:self.flushTimer forMode:NSRunLoopCommonModes];
}

- (void)addEvent:(NSDictionary *)event {
    if (!event) return;

    static NSSet *immediateEvents;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        immediateEvents = [NSSet setWithArray:@[@"ad_appId",@"ad_request",@"ad_fill",@"ad_impression", @"ad_impression_done", @"ad_click",@"purchase_success"]];
    });

    dispatch_async(self.syncQueue, ^{
        NSString *act = event[@"act"];
        [self.eventCache addObject:event];
        [self persistCacheToDisk];

        if ([immediateEvents containsObject:act]) {
            [self flushEvents];
        } else if (self.eventCache.count >= 15) {
            [self flushEvents];
        }
    });
}

- (void)flushEvents {
    __block NSArray *eventsToSend = nil;
    dispatch_async(self.syncQueue, ^{
        if (self.eventCache.count == 0) return;
        eventsToSend = [self.eventCache copy];
        [self.eventCache removeAllObjects];
        [self persistCacheToDisk];
        
        if (eventsToSend.count == 0) return;

        NSString *m_data = [BMSOpMergeEventBuilder buildMDataWithEvents:eventsToSend];
        NSString *traceId = [[NSUUID UUID] UUIDString];
        self.lastTraceId = traceId;

        NSMutableDictionary *params = [NSMutableDictionary dictionary];
        params[@"timestamp"] = @([BMSAppInfoHelper currentTimestamp]);
        params[@"nonce"] = [BMSAppInfoHelper generateNonce];
        params[@"app_name"] = [BMSInitializer shared].appName;
        params[@"channel"] = [BMSInitializer shared].channel;
        params[@"version"] = [BMSInitializer shared].version;
        params[@"uuid"] = [BMSInitializer shared].loginModel.uuid;
        params[@"m_data"] = m_data;
        params[@"b_t"] = @(0);
        params[@"use_service_time"] = @(1);
        NSString *sign = [BMSEncryptionUtil generateSignWithParams:params secret:kSecret isRealAuth:YES];
        [params setObject:sign forKey:kSign];

        [BMSAPIService uploadMergedReportWithParams:params traceId:traceId success:^(id responseObject) {
            int code = [responseObject[@"code"] intValue];
            if (code == 0) {
                self.totalUploadedCount += eventsToSend.count;
                NSLog(@"[BMSOpMergeReporter] 上传成功，共 %lu 条 \n【事件详情】：\n %@", (unsigned long)eventsToSend.count,params);
            } else {
                self.totalFailedCount += eventsToSend.count;
                [self restoreEvents:eventsToSend];
                NSLog(@"[BMSOpMergeReporter] 上传失败: %@", responseObject);
            }
        } failure:^(NSError *error) {
            self.totalFailedCount += eventsToSend.count;
            [self restoreEvents:eventsToSend];
            NSLog(@"[BMSOpMergeReporter] 网络异常上传失败: %@", error);
        }];
    });

    
}

- (void)restoreEvents:(NSArray *)failedEvents {
    dispatch_async(self.syncQueue, ^{
        [self.eventCache insertObjects:failedEvents atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, failedEvents.count)]];
        [self persistCacheToDisk];
    });
}

- (void)persistCacheToDisk {
    [[BMSOpMergeCacheManager shared] saveEvents:self.eventCache];
}

- (void)loadCacheFromDisk {
    NSArray *saved = [[BMSOpMergeCacheManager shared] loadCachedEvents];
    if ([saved isKindOfClass:[NSArray class]]) {
        [self.eventCache addObjectsFromArray:saved];
    }
}

- (void)appWillTerminate {
    [self flushEvents];
}

- (void)appDidEnterBackground {
    [self flushEvents];
}

- (void)appDidFinishLaunching {
    [self flushEvents];
}

- (void)dealloc {
    [self.flushTimer invalidate];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)setupWithLaunchConfig:(BMSLaunchConfigModel *)config {
    NSInteger interval = config.bmsUploadIntervalSec;
    self.uploadInterval = (interval > 0) ? interval : 30;
}


@end
